package com.darwin.darwinNet
{
	import com.adobe.serialization.json.JSON;
	import com.darwin.darwinDebug.NetLog;
	import com.darwin.darwinNet.events.NetErrorEvent;
	import com.darwin.darwinNet.events.NetEvent;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;

	/**
	 * 通讯类 支持Http通讯&Socket通讯 
	 * @author vanCopper
	 * 
	 */	
	public class Net extends EventDispatcher
	{
		private var _requestURL:String = "";
		private var _fHttp:FHttp;
		private var _fSocket:FSocket;
		private var _fAmf:FAmf;
		private var _protocol:String;
		private var _timeout:int = 30;
		
		/**
		 *  初始化命令是否完成
		 */		
		private var _initComplete:Boolean = false;
		
		private var _delaySend:Array = [];
		private var _cmdAdapter:IDataHandle;
		
		private var _netLog:Boolean = false;
		public function Net()
		{
			if(_instance == null){
				_instance = this;
				initNet();
			}
			else{throw new Error("实例化单例类出错-Net");}
		}
		
		protected function initNet():void
		{
			_fHttp = new FHttp();
			_fHttp.addEventListener(NetEvent.NET_COMPLETE,onDataComplete);
			_fHttp.addEventListener(NetErrorEvent.NET_IOERROR,onIOError);
			_fHttp.addEventListener(NetErrorEvent.TIMEOUT_ERROR,onTimeoutError);
			
			_fSocket = new FSocket();
			_fSocket.addEventListener(NetEvent.NET_COMPLETE,onDataComplete);
			_fSocket.addEventListener(NetErrorEvent.NET_IOERROR,onIOError);	
			
			_fAmf = new FAmf();
			_fAmf.addEventListener(NetEvent.NET_COMPLETE,onDataComplete);
			_fAmf.addEventListener(NetErrorEvent.NET_IOERROR,onIOError);	
		}
		
		public function set netStruct(netStruct:INetStruct):void
		{
			if(_fSocket)
			{
				_fSocket.netStruct = netStruct;
			}
		}
		
		public function get netStruct():INetStruct
		{
			if(_fSocket)return _fSocket.netStruct;
			return null;
		}
		
		/**
		 * 进行socket连接,如果不使用socket请不要调用此方法，
		 * 此方法不会判断通信协议，将根据传入的参数进行socket连接
		 */
		public function connect(host:String,port:String):void
		{
			_fSocket.connectMulti(host,port);
		}
		
		/**
		 * 进行AMF连接，如果不使用AMF通讯请不要调用此方法
		 * @param endpoint 服务器端入口地址
		 * @param source 要连接的对象名称
		 * @param method 要调用对象的方法名
		 */		
		public function connectAmf(endpoint:String,source:String,method:String):void
		{
			_fAmf.connectAmf(endpoint,source,method);
		}
		
		protected function onTimeoutError(event:Event):void
		{
			dispatchEvent(event);
		}
		
		protected function onIOError(event:NetErrorEvent):void
		{
			var errorEvent:NetErrorEvent = new NetErrorEvent(NetErrorEvent.NET_IOERROR);
			dispatchEvent(errorEvent);
		}
		
		protected function onDataComplete(event:NetEvent):void
		{
			var data:Object = event.data;
			var method:String = "";
			var result:String = "";
			var msg:String = "";
			var info:Object;
			
			if(data.hasOwnProperty("method"))
			{
				method = data["method"];
			}
			
			if(method == INIT_CMD)
			{
				_initComplete = true;
				delaySend();
			}
			
			if(data.hasOwnProperty("result"))
			{
				result = data["result"];
			}
			
			if(data.hasOwnProperty("msg"))
			{
				msg = data["msg"];
			}
			
			if(data.hasOwnProperty("info"))
			{
				info = data["info"];
			}
			
			//netLog yuri
			if(netLog  && protocol == PROTOCOL_SOCKET && info){
				NetLog.getInstance().netReceive(data,info);
			}
			
			if(result != "0" || result == "")
			{
				var errorEvent:NetErrorEvent = new NetErrorEvent(NetErrorEvent.NET_ERROR,data);
				errorEvent.errorCode = result;
				errorEvent.errorMsg = msg;
				errorEvent.cmd = method;
				dispatchEvent(errorEvent);
			}else
			{
				dispatchEvent(new NetEvent(method,data));
				if(info)
				{
					for(var cmd:String in info)
					{
						if(_handleDic[cmd])
						{
							var dataHandle:IDataHandle = _handleDic[cmd] as IDataHandle;
							dataHandle.dataHandle(info[cmd]);
						}
						if(_cmdAdapter)
						{
							_cmdAdapter.cmdDataHandle(cmd,info[cmd]);
						}
						var netEvent:NetEvent = new NetEvent(cmd,info[cmd]);
						dispatchEvent(netEvent);
					}
				}
			}
		}
		
		private static var _instance:Net;
		
		public static function getInstance():Net
		{
			if(_instance == null)
				_instance = new Net();
			
			return _instance;
		}
		
		private var _handleDic:Dictionary = new Dictionary();
		/**
		 * 为对应命令注册处理类 
		 * @param cmd
		 * @param dataHandle
		 * 
		 */		
		public function registerModelHandle(cmd:String,dataHandle:IDataHandle):void
		{
			_handleDic[cmd] = dataHandle;
		}
		
		/**
		 * 发送请求
		 * @param cmd 要发送的请求命令
		 * @param data 要发送的数据
		 * @param other 其他数据
		 * @param method post/get
		 * @param front 要追加到BODY前端的字符信息(仅socket可选,http不可用)
		 */		
		public function send(cmd:String,data:Object,other:Object=null,method:String = HTTP_POST,front:String = ""):void
		{
			//TODO socket通讯时 加入新的协议数据发送
			if(protocol == PROTOCOL_HTTP)
			{
				httpSend(cmd,data,other,method);
			}
			else if(protocol == PROTOCOL_AMF)
			{
				amfSend(cmd,data);
			}
			else
			{
				socketSend(cmd,data,other,0,front);
			}
			
		}
		
		/**
		 * 发送http请求 
		 * @param cmd 要发送的请求命令
		 * @param data 要发送的数据
		 * @param other 其他数据
		 * @param method post/get
		 */		
		public function httpSend(cmd:String,data:Object,other:Object = null,method:String = HTTP_POST):void
		{
			if(cmd == INIT_CMD)
			{
				_fHttp.send(cmd,data,requestURL,other,method);
			}else if(!_initComplete)
			{
				_delaySend.push([cmd,data,other,method]);
			}else
			{
				_fHttp.send(cmd,data,requestURL,other,method);
			}
		}
		
		/**
		 * 初始化命令完成后 发出延迟命令 
		 * 
		 */		
		private function delaySend():void
		{
			for (var i:int = 0; i < _delaySend.length; i++) 
			{
				var arr:Array = _delaySend[i];
				_fHttp.send(arr[0],arr[1],arr[2],arr[3]);
			}
			_delaySend.length = 0;			
		}
		
		
		/**
		 * 发送socket请求
		 * @param cmd
		 * @param data
		 * @param other
		 * @param res
		 * @param front 要追加到body字符串最前端的信息(可用于网关判断分配服务器时使用)
		 */		
		public function socketSend(cmd:String,data:Object,other:Object = null,res:int = 0,front:String = ""):void
		{
			if(netLog){
				NetLog.getInstance().netSend(cmd,data);
			}
			var dataByte:ByteArray = new ByteArray();
			var dataStr:String = com.adobe.serialization.json.JSON.encode(data);
			dataByte.writeUTFBytes(front + dataStr);
			trace("send........发送命令:" + cmd + ".....data:" + dataStr);
			_fSocket.send(cmd,dataByte,res);
		}
		
		//是否结构体通讯
		public var isStructMessage:Boolean = false;
		/**
		 * 发送结构体socket通讯 
		 * @param cmd
		 * @param param
		 * @param data
		 * 
		 */		
		public function sendStruct(cmd:uint,param:uint,time:uint,data:Object):void
		{
			_fSocket.isStructMessage = true;
			var strutAnalyzer:StructAnalyzer = new StructAnalyzer();
			var sendData:ByteArray = strutAnalyzer.encode(cmd,param,time,data,netStruct.getNetStruct(""+cmd,""+param));
			_fSocket.sendStruct(sendData);
		}
		
		/**
		 * 发送AMF请求
		 * @param cmd 要发送的请求命令
		 * @param data 要发送的数据
		 */		
		public function amfSend(cmd:String,data:Object):void
		{
			if(data==null)
				return;
			data["method"] = cmd;
			_fAmf.send(data);
		}
		
		/**
		 * 关闭socket连接 
		 * 
		 */		
		public function closeSocket():void
		{
			(_fSocket.connected)
			{
				_fSocket.close();
			}
		}
		
		/**
		 * 发送文件流 
		 * @param cmd 接口名
		 * @param fileData 文件二进制数据
		 * @param fileName 文件保存名称
		 * 
		 */		
		public function sendFile(cmd:String,fileData:ByteArray,fileName:String = ""):void
		{
			_fHttp.sendFile(cmd,fileData,requestURL,fileName);
		}
		
		/**
		 * webServer 通讯地址 
		 */
		public function get requestURL():String
		{
			return _requestURL;
		}

		/**
		 * @private
		 */
		public function set requestURL(value:String):void
		{
			_requestURL = value;
		}

		/**
		 * 网络通讯协议 默认为  Net.PROTOCOL_HTTP
		 * Net.PROTOCOL_HTTP/Net.PROTOCOL_SOCKET/Net.PROTOCOL_AMF
		 */
		public function get protocol():String
		{
			return _protocol;
		}

		/**
		 * @private
		 */
		public function set protocol(value:String):void
		{
			_protocol = value;
		}

		/**
		 * 命令请求超时时间 
		 */
		public function get timeout():int
		{
			return _timeout;
		}

		/**
		 * @private
		 */
		public function set timeout(value:int):void
		{
			_timeout = value;
			if(_fHttp)
			{
				_fHttp.timeout = _timeout;
			}
		}

		/**
		 * 命令解析适配器 
		 */
		public function set cmdAdapter(value:IDataHandle):void
		{
			_cmdAdapter = value;
		}

		public function get netLog():Boolean
		{
			return _netLog;
		}

		public function set netLog(value:Boolean):void
		{
			_netLog = value;
		}
		
		
		public static const HTTP_POST:String = "post";
		public static const HTTP_GET:String = "get";
		public static const PROTOCOL_HTTP:String = "http";
		public static const PROTOCOL_SOCKET:String = "socket";
		public static const PROTOCOL_AMF:String = "amf";
		public static const INIT_CMD:String = "Scene.init";
	}
}